/**
 * Copyrigt (2020, ) Institute of Software, Chinese Academy of Sciences
 */
package com.springutil.dao;

import com.springutil.model.AbstracteGenerator;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

/**
 * 根据modelDao生成modelService
 *
 * @author wuheng@iscas.ac.cn
 * @since 2020.2.10
 * mysqldump -h 172.17.0.2 -u root -p demo user> dbname_users.sql
 */
public class ServiceGenerator extends AbstracteGenerator {

    public static final String COPYRIGHT = "/**\r\n" +
            " * Copyrigt (2020, ) Institute of Software, Chinese Academy of Sciences\r\n" +
            " */\n";

    public static final String PACKAGE = "package PACKAGE_NAME;\n\n";

    public static final String IMPORT = "import IMPORT_NAME;\n";

    public static final String CLASS = "/**\r\n" +
            " * This code is auto-generated by <code>ServiceGenerator<code>\r\n" +
            " *\r\n" +
            " * @author jiaohongtao\r\n" + " */\n"
            + "public class CLASS_NAME {\n\n";

    public static final String FIELD = "\t@Autowired\n\tprivate FIELD_TYPE FIELD_NAME;\n\n";

    public static final String METHOD = "\tpublic METHOD_TYPE METHOD_NAME(";

    public static final String PROXY = "PROXY_NAME.PROXY_METHOD(PROXY_PARAM)";

    public static final String THROW = " throws EXCEPTION ";

    public static final String RETURN = "\t\treturn ";

    public static final String VOID = "\t\t ";

    public static final String END_PARAM = ")";

    public static final String CONSTRUCT_START = "{\n";

    private static final String END_CLASS = "}";

    public static final String END_METHOD = ";\n\t}\n\n";

    private List<String> importList = new ArrayList<>();

    private String pkgName;

    protected Class<?> modelClass;


    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }

    public Class<?> getModelClass() {
        return modelClass;
    }

    public void setModelClass(Class<?> modelClass) {
        this.modelClass = modelClass;
    }

    /*******************************************
     *
     *    Core
     *
     *******************************************/
    public void createServiceFromDao(String classname) throws Exception {
        createServiceFromDao(Class.forName(classname));
    }

    public void createServiceFromDao(Class<?> clazz) throws Exception {
        String serviceName = getServiceName(clazz);

        initImportList(clazz);
        StringBuffer generateMethods = generateMethods(clazz);

        content.append(COPYRIGHT);
        content.append(PACKAGE.replace("PACKAGE_NAME", this.getPkgName()));
        content.append(getImports()).append("\n");
        content.append(CLASS.replace("CLASS_NAME", serviceName));
        content.append(FIELD.replace("FIELD_TYPE", clazz.getSimpleName()).replace("FIELD_NAME", fieldName(clazz)));
        content.append(generateMethods);
        content.append(END_CLASS);
    }

    private String getServiceName(Class<?> clazz) throws Exception {
        String daoPackage = clazz.getPackage().getName();
        String parentPackage = daoPackage.substring(0, daoPackage.lastIndexOf("."));
        this.setPkgName(parentPackage + ".serfieldNamevice");
        this.setDir("/src/main/java/" + parentPackage + ".service");
        String serviceName = clazz.getSimpleName().replace("Dao", "Service");
        this.setName(serviceName + ".java");
        String modelName = clazz.getSimpleName().replace("Dao", "");
        this.setModelClass(Class.forName(parentPackage + ".model." + modelName));
        return serviceName;
    }


    /*******************************************
     *
     *    Import
     *
     *******************************************/

    private void initImportList(Class<?> clazz) {
        importList.add(Autowired.class.getName());
        importList.add(clazz.getName());
        importList.add(modelClass.getName());
    }

    private void addImport(String packageName) {
        if (!importList.contains(packageName) &&
                !packageName.startsWith("java.lang") &&
                packageName.contains(".")) {
            importList.add(packageName);
        }
    }

    private String getImports() {
        StringBuilder sb = new StringBuilder();
        for (String im : importList) {
            sb.append(IMPORT.replace("IMPORT_NAME", im));
        }
        return sb.toString();
    }

    /*******************************************
     *
     *    Field
     *
     *******************************************/

    private String fieldName(Class<?> clazz) {
        return clazz.getSimpleName().substring(0, 1).toLowerCase()
                + clazz.getSimpleName().substring(1);
    }

    /*******************************************
     *
     *    Methods
     *
     *******************************************/

    private StringBuffer generateMethods(Class<?> clazz) throws Exception {
        StringBuffer msb = new StringBuffer();

        for (Method method : clazz.getDeclaredMethods()) {
            // return
            msb.append(METHOD.replace("METHOD_TYPE", method.getGenericReturnType().getTypeName())
                    .replace("METHOD_NAME", method.getName()));

            // method name
            StringBuilder psb = new StringBuilder();
            for (Parameter param : method.getParameters()) {
                addImport(param.getType().getTypeName());

                // return方法参数
                psb.append(param.getName()).append(", ");
                // 方法参数
                msb.append(param.getParameterizedType().getTypeName()).append(" ").append(param.getName()).append(", ");
            }

            if (psb.length() > 2) {
                psb.delete(psb.length() - 2, psb.length());
                msb.delete(msb.length() - 2, msb.length());
            }

            msb.append(END_PARAM);

            StringBuilder sb = new StringBuilder();
            for (Class<?> cla : method.getExceptionTypes()) {
                // Exception
                sb.append(cla.getSimpleName()).append(", ");
            }
            msb.append(THROW.replace("EXCEPTION", sb.substring(0, sb.length() - 2)));
            msb.append(CONSTRUCT_START);

            // method body
            if (!"void".equals(method.getReturnType().getSimpleName())) {
                msb.append(RETURN);
            } else {
                msb.append(VOID);
            }

            msb.append(PROXY.replace("PROXY_NAME", fieldName(clazz))
                    .replace("PROXY_METHOD", method.getName())
                    .replace("PROXY_PARAM", psb.toString()));


            // method complete
            msb.append(END_METHOD);
        }
        return msb;
    }

    public static void main(String[] args) throws Exception {
        ServiceGenerator sg = new ServiceGenerator();
        sg.createServiceFromDao("com.spring_util.dao.CmdbRelationTypeDao");
        sg.print();
        sg.write();
    }
}
